
#include "QBIssuerInfo.h"
#include "ZippedObjectMap.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
//#define new DEBUG_NEW
#endif

#ifndef BASSERT
#define BASSERT //
#endif // !BASSERT

#define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
#define FIELD_OFFSET(type, field)    offsetof(type, field)

//////////////////////////////////////////////////////////////////////
// class CQBIssuerInfo
void StringArray::Destroy(StringArray* sarray)
{
	if (sarray)
		std::free(sarray);
}

StringArray* StringArray::Create(const void* data, const StringOffsets& soffsets, int* pbytes)
{
	typedef qb::base::strinfo strinfo;
	qb::base::StackArray<strinfo, 128> stroffsets;
	int bytes = 0;
	for (int i = 0; i < (int)soffsets.size(); i++)
	{
		const strinfo& si = soffsets[i];
		int len = strlen((const char*)data + si.pos);
		stroffsets.Add(strinfo{ si.pos, len });
		bytes += len + 1;
	}
	int flag = bytes > 255 ? 1 : 0;
	int offunit = flag == 1 ? sizeof(ushort) : sizeof(uchar);
	bytes += sizeof(ushort) + soffsets.size()*offunit;
	char* buf = (char*)std::malloc(bytes);
	memset(buf, 0, bytes);
	char* base = buf + sizeof(ushort) + soffsets.size()*offunit;
	StringArray* sarray = new (buf)StringArray(flag, soffsets.size());
	char* dest = base;
	int pos = 0;
	uchar* coffsets = (uchar*)(buf + sizeof(ushort));
	ushort* uoffsets = (ushort*)(buf + sizeof(ushort));
	for (int i = 0; i < (int)stroffsets.size(); i++)
	{
		if (flag == 1)uoffsets[i] = pos;
		else coffsets[i] = pos;
		strncpy(dest + pos, ((const char*)data) + stroffsets[i].pos, stroffsets[i].len);
		pos += stroffsets[i].len + 1;
	}
	if (pbytes)*pbytes = bytes;
	int calcbytes = sarray->bytes();
	BASSERT(calcbytes == bytes);
	bool suc = sarray->check(data, soffsets);
	BASSERT(suc);
	return sarray;
}

const char* StringArray::base() const
{
	const char* end = (const char*)(this + 1);
	end += m_count*(m_flag ? sizeof(ushort) : sizeof(uchar));
	return end;
}

int StringArray::offset(int index) const
{
	if (m_flag){
		return ((ushort*)(this + 1))[index];
	}
	else
		return ((uchar*)(this + 1))[index];
}

int StringArray::bytes() const
{
	const char* start = base();
	const char* str = start + offset(m_count - 1);
	const char* end = str + strlen(str) + 1;
	return end - (const char*)(this);
}

const char* StringArray::field(int index) const
{
	const char* start = base();
	start += offset(index);
	return start;
}
const char* StringArray::field(kIssuerInfo index)const
{
	const char* start = base();
	start += offset((int)index);
	return start;

}

bool StringArray::check(const void* data, const StringOffsets& soffsets) const
{
	if (count() != soffsets.size())return false;
	for (int i = 0; i < (int)soffsets.size(); i++)
	{
		const char* fd = field(i);
		const char* raw = ((const char*)data) + soffsets[i].pos;
		if (0 != strcmp(fd, raw))
			return false;
	}
	return true;
}
IssuerStringOffsets::IssuerStringOffsets(){
	this->reserve(17);
	Add(FIELD_OFFSET(QBISSUERINFO, Institution_Code), RTL_FIELD_SIZE(QBISSUERINFO, Institution_Code));
	Add(FIELD_OFFSET(QBISSUERINFO, Full_Name_C), RTL_FIELD_SIZE(QBISSUERINFO, Full_Name_C));
	Add(FIELD_OFFSET(QBISSUERINFO, Issuer_Type), RTL_FIELD_SIZE(QBISSUERINFO, Issuer_Type));
	Add(FIELD_OFFSET(QBISSUERINFO, SW_Sector_Code), RTL_FIELD_SIZE(QBISSUERINFO, SW_Sector_Code));
	Add(FIELD_OFFSET(QBISSUERINFO, SW_Subsector_Code), RTL_FIELD_SIZE(QBISSUERINFO, SW_Subsector_Code));
	Add(FIELD_OFFSET(QBISSUERINFO, SW_2021_Sector_Code), RTL_FIELD_SIZE(QBISSUERINFO, SW_2021_Sector_Code));
	Add(FIELD_OFFSET(QBISSUERINFO, SW_2021_Subsector_Code), RTL_FIELD_SIZE(QBISSUERINFO, SW_2021_Subsector_Code));
	Add(FIELD_OFFSET(QBISSUERINFO, Province_Code), RTL_FIELD_SIZE(QBISSUERINFO, Province_Code));
	Add(FIELD_OFFSET(QBISSUERINFO, Short_Name_C), RTL_FIELD_SIZE(QBISSUERINFO, Short_Name_C));
	Add(FIELD_OFFSET(QBISSUERINFO, Full_Name_E), RTL_FIELD_SIZE(QBISSUERINFO, Full_Name_E));
	Add(FIELD_OFFSET(QBISSUERINFO, Short_Name_E), RTL_FIELD_SIZE(QBISSUERINFO, Short_Name_E));
	Add(FIELD_OFFSET(QBISSUERINFO, Listed_Type), RTL_FIELD_SIZE(QBISSUERINFO, Listed_Type));
	Add(FIELD_OFFSET(QBISSUERINFO, Actual_Controller_Name), RTL_FIELD_SIZE(QBISSUERINFO, Actual_Controller_Name));
	Add(FIELD_OFFSET(QBISSUERINFO, Actual_Controller_Type), RTL_FIELD_SIZE(QBISSUERINFO, Actual_Controller_Type));
	Add(FIELD_OFFSET(QBISSUERINFO, Rate), RTL_FIELD_SIZE(QBISSUERINFO, Rate));
	Add(FIELD_OFFSET(QBISSUERINFO, CBRC_Financing_Platform), RTL_FIELD_SIZE(QBISSUERINFO, CBRC_Financing_Platform));
	Add(FIELD_OFFSET(QBISSUERINFO, Municipal_code), RTL_FIELD_SIZE(QBISSUERINFO, Municipal_code));
}
IssuerStringOffsets& IssuerStringOffsets::Get(){
	static IssuerStringOffsets sOffsets;
	return sOffsets;
}

CQBIssuerInfo::CQBIssuerInfo():m_stateid(0)
{
	//IssuerRegister::Get();
	//m_zip = new IssueObjectMap();
}

CQBIssuerInfo::~CQBIssuerInfo()
{
	Clear( );
	//if (m_zip)
	//	delete m_zip;
}

bool CQBIssuerInfo::Clear( )
{
	std::lock_guard<std::mutex>	l(m_mutex);
	for (auto it = m_map.begin(); it != m_map.end();++it)
		StringArray::Destroy(it->second);
	m_map.clear();
	m_stateid++;
	return true;
}

bool CQBIssuerInfo::Add( const QBISSUERINFO & info ){
	if(info.Institution_Code[0]=='\0')
		return false;
	//EncodeIssuerInfo(info);
	qb::base::KeyString key(info.Institution_Code);
	std::lock_guard<std::mutex>	l(m_mutex);
	auto it = m_map.find(key);
	if (it != m_map.end())
	{
		StringArray::Destroy(it->second);
		m_map.erase(it);
	}
	m_map[key] = StringArray::Create(&info, IssuerStringOffsets::Get());
	//m_map[info.Institution_Code] = info;
	m_stateid++;
	return true;
}
int	CQBIssuerInfo::GetStateId()
{
	std::lock_guard<std::mutex>	l(m_mutex);
	return m_stateid;
}

const IssuerInfo* CQBIssuerInfo::GetIssuerInfo(const std::string &id)
{
	const auto& it = m_map.find(id);
	if(it != m_map.end()){
		return it->second;
	}
	return nullptr;
}

void CQBIssuerInfo::DumpStatus(int mode)const
{
	//if (!qb::base::cfg::GetConfigBool(qb::base::kBaseConfigMetricMemory))
	//	return;
	//CSPMutex::Scoped	l(const_cast<CSPMutex&>(m_mutex));
	//class SizeGetter{
	//public:
	//	static int GetItemRealSize(const QBISSUERINFO& info)
	//	{
	//		int size = strlen(info.Institution_Code) + 1;
	//		size += strlen(info.Full_Name_C) + 1;
	//		//size += strlen(info.Jianpin) + 1;
	//		//size += strlen(info.Quanpin) + 1;
	//		size += strlen(info.Issuer_Type) + 1;
	//		size += strlen(info.SW_Sector_Code) + 1;
	//		size += strlen(info.SW_Subsector_Code) + 1;
	//		size += strlen(info.SW_2021_Sector_Code) + 1;
	// 	   	size += strlen(info.SW_2021_Subsector_Code) + 1;
	//		size += strlen(info.Province_Code) + 1;
	//		size += strlen(info.Short_Name_C) + 1;
	//		size += strlen(info.Full_Name_E) + 1;
	//		size += strlen(info.Short_Name_E) + 1;
	//		size += strlen(info.Listed_Type) + 1;
	//		size += strlen(info.Actual_Controller_Name) + 1;
	//		size += strlen(info.Actual_Controller_Type) + 1;
	//		size += strlen(info.Rate) + 1;
	//		size += strlen(info.CBRC_Financing_Platform) + 1;
	//		size += strlen(info.Municipal_code) + 1;
	//		return size;
	//	}
	//	static int GetItemAllSize(const QBISSUERINFO& info)
	//	{
	//		int size = sizeof(QBISSUERINFO);
	//		return size;
	//	}
	//};
	//qb::base::StringUtil::DumpMapStatus<IssuerInfoMap, SizeGetter>(m_map,"CQBIssuerInfo");

}

CQBIssuerInfo& CQBIssuerInfo::instance()
{
	static CQBIssuerInfo s_ii;
	return s_ii;
}

CQBIssuerInfo& CQBIssuerInfo::MainUnderwriterContainer()
{
	static CQBIssuerInfo s_ii2;
	return s_ii2;
}

CQBIssuerInfo& CQBIssuerInfo::ABSBondSeries()
{
	static CQBIssuerInfo s_ii3;
	return s_ii3;
}
